package ai.koog.prompt.executor.model

import ai.koog.agents.core.tools.ToolDescriptor
import ai.koog.prompt.dsl.ModerationResult
import ai.koog.prompt.dsl.Prompt
import ai.koog.prompt.llm.LLModel
import ai.koog.prompt.message.LLMChoice
import ai.koog.prompt.message.Message
import ai.koog.prompt.streaming.StreamFrame
import kotlinx.coroutines.flow.Flow

/**
 * An interface representing an executor for processing language model prompts.
 * This defines methods for executing prompts against models with or without tool assistance,
 * as well as for streaming responses.
 *
 * Implements [AutoCloseable] as prompt executors typically work with LLM clients. Always close it when finished.
 *
 * Note: a single [PromptExecutor] might embed multiple LLM clients for different LLM providers supporting different models.
 */
public interface PromptExecutor : AutoCloseable {

    /**
     * Executes a given prompt using the specified language model and tools, returning a list of responses from the model.
     *
     * @param prompt The `Prompt` object containing the messages to be used in the execution.
     * @param model The instance of `LLModel` that specifies the language model to be used.
     * @param tools A list of `ToolDescriptor` objects that define the tools available for the execution.
     * @return A list of `Message.Response` objects representing the responses generated by the language model.
     */
    public suspend fun execute(
        prompt: Prompt,
        model: LLModel,
        tools: List<ToolDescriptor> = emptyList()
    ): List<Message.Response>

    /**
     * Executes a given prompt using the specified language model and returns a stream of output as a flow of `StreamFrame` objects.
     *
     * @param prompt The prompt containing input messages and parameters to guide the language model execution.
     * @param model The language model to be used for processing the prompt.
     * @param tools A list of `ToolDescriptor` objects that define the tools available for the execution.
     * @return A flow emitting `StreamFrame` objects that represent the streaming output of the language model.
     */
    public fun executeStreaming(
        prompt: Prompt,
        model: LLModel,
        tools: List<ToolDescriptor> = emptyList()
    ): Flow<StreamFrame>

    /**
     * Receives multiple independent choices from the LLM.
     * The method is implemented only for some specific providers which support multiple LLM choices.
     *
     * @param prompt The prompt containing input messages and parameters to guide the language model execution.
     * @param model The language model to be used for processing the prompt.
     * @param tools A list of `ToolDescriptor` objects that define the tools available for the execution.
     * @return A list of `LLMChoice` objects representing the responses generated by the language model.
     */
    public suspend fun executeMultipleChoices(
        prompt: Prompt,
        model: LLModel,
        tools: List<ToolDescriptor>
    ): List<LLMChoice> =
        listOf(execute(prompt, model, tools))

    /**
     * Moderates the content of a given message with attachments using a specified language model.
     *
     * This method evaluates the content of the message and its attachments to determine
     * if it complies with content guidelines. The moderation is performed using the provided
     * language model, which analyzes the content and returns a detailed moderation result.
     *
     * @param model The language model that will be used to perform the moderation.
     * @return A `ModerationResult` containing information about the moderation outcome,
     *         including flagged categories, scores, and whether the content is classified
     *         as harmful.
     */
    public suspend fun moderate(prompt: Prompt, model: LLModel): ModerationResult

    /**
     * Retrieves a list of available models from all LLM clients managed by this executor.
     *
     * This method aggregates models from all configured LLM providers and clients,
     * returning a comprehensive list of available language models that can be used
     * with this executor.
     *
     * @return A list of [LLModel] instances representing all available models.
     */
    public suspend fun models(): List<String> {
        throw UnsupportedOperationException("Not implemented for this executor")
    }
}
